/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2023. All rights reserved.
 *
 * Created on: 2019-10-10
 *
 */

#ifndef UDK_USRNL_IN_H
#define UDK_USRNL_IN_H

#include <bits/sockaddr.h>
#include <stdint.h>

#include "udk_spinlock.h"

#define USRNL_SOCK_NUM 16
#define USRNL_CMD_NUM 32

/* some macroes and enumeration not used, should not put them in .c */
/* netlink protocol message */
#define NLM_F_REQUEST 0x001
#define NLM_F_DUMP (NLM_F_ROOT | NLM_F_MATCH)

#define NLMSG_NOOP 0x1    /* Nothing.		*/
#define NLMSG_ERROR 0x2   /* Error		*/
#define NLMSG_DONE 0x3    /* End of a dump	*/
#define NLMSG_OVERRUN 0x4 /* Data lost		*/
#define NLMSG_MIN_TYPE 0x10

#define NETLINK_GENERIC 16
#define GENL_ID_CTRL NLMSG_MIN_TYPE

/* Returns X / Y, rounding up.  X must be nonnegative to round correctly. */
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y))
#endif

/* Returns X rounded up to the nearest multiple of Y. */
#ifndef ROUND_UP
#define ROUND_UP(X, Y) (DIV_ROUND_UP(X, Y) * (Y))
#endif

/* message header length */
#define USRNL_ALIGNTO 4
#define USRNL_ALIGN(SIZE) ROUND_UP(SIZE, USRNL_ALIGNTO)
#define USRNL_HDRLEN ((int)USRNL_ALIGN(sizeof(struct usrnl_msghdr)))

/* generic message header length */
#define USRNL_GENL_HDRLEN USRNL_ALIGN(sizeof(struct genlmsghdr))

/* NL message header length */
#define USRNL_NLA_ALIGNTO 4
#define USRNL_NLA_ALIGN(SIZE) ROUND_UP(SIZE, USRNL_NLA_ALIGNTO)
#define USRNL_NLA_HDRLEN ((int)USRNL_NLA_ALIGN(sizeof(struct usrnl_nlattr)))

#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)

#define VPMD_NLM_RCV_BUF_SIZE (8 * 1024 * 1024)

#define USRNL_FLUSH_TRY_TIMES 10
#define USRNL_FLUSH_WAIT_ONCE_US 1000

enum {
    UDK_CTRL_CMD_UNSPEC,
    UDK_CTRL_CMD_NEWFAMILY,
    UDK_CTRL_CMD_DELFAMILY,
    UDK_CTRL_CMD_GETFAMILY,
    UDK_CTRL_CMD_NEWOPS,
    UDK_CTRL_CMD_DELOPS,
    UDK_CTRL_CMD_GETOPS,
    UDK_CTRL_CMD_MAX,
};

enum {
    UDK_CTRL_ATTR_UNSPEC,
    UDK_CTRL_ATTR_FAMILY_ID,
    UDK_CTRL_ATTR_FAMILY_NAME,
    UDK_CTRL_ATTR_VERSION,
    UDK_CTRL_ATTR_HDRSIZE,
    UDK_CTRL_ATTR_MAXATTR,
    UDK_CTRL_ATTR_OPS,
    UDK_CTRL_ATTR_MAX,
};

enum {
    USRNL_STATUS_NORMAL,
    USRNL_STATUS_BLOCK,
};

typedef enum {
    USRNL_PROCESS_CPL,
    USRNL_PROCESS_WAITING,
    USRNL_PROCESS_ERR,
} usrnl_wait_return;

typedef usrnl_wait_return (* usrnl_wait_cpl_handler)(void *priv_data);

/* do not change member order */
struct usrnl_sockaddr {
    sa_family_t nl_family; /* AF_NETLINK	*/
    uint16_t nl_pad;       /* zero		*/
    uint32_t nl_pid;       /* port ID	*/
    uint32_t nl_groups;    /* multicast groups mask */
};

/* do not change member order */
struct usrnl_msghdr {
    uint32_t nlmsg_len;
    uint16_t nlmsg_type;
    uint16_t nlmsg_flags;
    uint32_t nlmsg_seq;
    uint32_t nlmsg_pid;
};

struct usrnl_msgerr {
    int error;
    struct usrnl_msghdr msg;
};

struct genlmsghdr {
    uint8_t cmd;
    uint8_t version;
    uint16_t reserved;
};

struct usrnl_nlattr {
    uint16_t nla_len;
    uint16_t nla_type;
};

/* socket for netlink */
struct usrnl_sock {
    int fd;
    uint32_t next_seq;
    uint32_t pid;
    int protocol;

    /* Receive buffer size (SO_RCVBUF). */
    unsigned int rcvbuf;
};

/* socket pool */
struct usrnl_sock_pool {
    struct usrnl_sock *socks[USRNL_SOCK_NUM];
    int n;
};

/* cmd buffer pool */
struct usrnl_cmd_pool {
    struct usrnl_cmd_buf *cmd_bufs[USRNL_CMD_NUM];
    int n;
};

/* udk netlink object */
struct udk_usrnl {
    uint32_t usrnl_status;
    uint32_t usrnl_family_id;

    udk_spinlock_t sock_pool_lock;
    struct usrnl_sock_pool sock_pool;
    int total_active_sock;

    udk_spinlock_t cmd_pool_lock;
    struct usrnl_cmd_pool cmd_pool;
};

#endif
